package belf.migrate.engine.ddl.function.mysql;

import belf.migrate.api.util.QuoteType;
import belf.migrate.core.jdbc.FunctionModel;
import belf.migrate.core.jdbc.TypeModel;
import belf.migrate.engine.ddl.BaseDDLConvert;
import belf.migrate.plugin.mysql.antlr.MySqlParser;
import belf.migrate.plugin.mysql.antlr.MySqlParserBaseVisitor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * MySql函数的visitor遍历器
 */
public class MySqlFunctionVisitor extends MySqlParserBaseVisitor<String> {
    //以下5个参数为构造参数
    private BaseDDLConvert ddlConvert;
    private String quote = "\"";
    private String schema;
    private Map<String, FunctionModel> funcMapping;
    private Map<String, TypeModel> typeMapping;

    //函数名称
    private String functionName;
    //参数列表
    private List<MySqlParser.FunctionParameterContext> parameters;
    //返回值
    private String returnType;
    // MySql函数定义里，参数申明在BEGIN..END之间，在达梦的函数定义里参数申明需要提到BEGIN之前
    private List<MySqlParser.DeclareVariableContext> variables;
    // BEGIN...END之间的函数定义语句
    private List<MySqlParser.ProcedureSqlStatementContext> procedureSqls;

    public MySqlFunctionVisitor(BaseDDLConvert ddlConvert,
                                String schema,
                                Map<String, FunctionModel> funcMapping,
                                Map<String, TypeModel> typeMapping) {
        this.ddlConvert = ddlConvert;
        this.quote = QuoteType.DOUBLE_QUOTE.getValue();
        this.schema = schema;
        this.funcMapping = funcMapping;
        this.typeMapping = typeMapping;

        parameters = new ArrayList<>();
        variables = new ArrayList<>();
        procedureSqls = new ArrayList<>();
    }

    @Override
    public String visitCreateFunction(MySqlParser.CreateFunctionContext ctx) {
        functionName = ctx.fullId().getText();
        functionName = functionName.replace("`", quote);
        if (functionName.indexOf('.') == -1) {
            functionName = quote + schema + quote + '.' + functionName;
        }

        returnType = ctx.dataType().getText().trim();
        if (typeMapping.containsKey(returnType)) {
            returnType = typeMapping.get(returnType).getTo();
        }
        return visitChildren(ctx);
    }

    @Override
    public String visitFunctionParameter(MySqlParser.FunctionParameterContext ctx) {
        if (BaseDDLConvert.hasAncestor("CreateFunctionContext", ctx)) {
            parameters.add(ctx);
        }
        return visitChildren(ctx);
    }

    @Override
    public String visitDeclareVariable(MySqlParser.DeclareVariableContext ctx) {
        variables.add(ctx);

        return visitChildren(ctx);
    }

    @Override
    public String visitProcedureSqlStatement(MySqlParser.ProcedureSqlStatementContext ctx) {
        // 排除子句重复查找
        if (!(BaseDDLConvert.hasAncestor("ProcedureSqlStatementContext", ctx))) {
            procedureSqls.add(ctx);
        }

        return visitChildren(ctx);
    }

    public String getFunctionName() {
        return functionName;
    }

    public List<MySqlParser.FunctionParameterContext> getParameters() {
        return parameters;
    }

    public String getReturnType() {
        return returnType;
    }

    public List<MySqlParser.DeclareVariableContext> getVariables() {
        return variables;
    }

    public List<MySqlParser.ProcedureSqlStatementContext> getProcedureSqls() {
        return procedureSqls;
    }
}
